package com.cosw.sdkShanghaiCA;

import static com.cosw.sdkShanghaiCA.EnumError.ENV_NOT_INIT;
import static com.cosw.sdkShanghaiCA.EnumError.NO_FOUND_ALG_ERROR;
import static com.cosw.sdkShanghaiCA.SDKConstant.CMD_SELECT_AID;

import android.app.Application;
import android.bluetooth.BluetoothAdapter;
import android.bluetooth.BluetoothDevice;
import android.bluetooth.BluetoothManager;
import android.content.Context;
import android.content.pm.PackageManager;
import android.os.Handler;
import android.widget.Toast;
import com.cosw.util.Logz;
import com.cosw.util.StringUtil;
import com.cosw.util.TLVTools;
import java.io.ByteArrayInputStream;
import java.io.UnsupportedEncodingException;
import java.math.BigInteger;
import java.security.KeyFactory;
import java.security.NoSuchAlgorithmException;
import java.security.cert.CertificateException;
import java.security.cert.CertificateFactory;
import java.security.cert.X509Certificate;
import java.security.interfaces.RSAPublicKey;
import java.security.spec.InvalidKeySpecException;
import java.security.spec.RSAPublicKeySpec;
import java.security.spec.X509EncodedKeySpec;
import java.util.ArrayList;
import java.util.List;
import java.util.Vector;

public class SHCAProvider {

  private NzBleUtil bleUtil;
  private static SHCAProvider bleProvider;
  private BluetoothAdapter mBluetoothAdapter;
  private BluetoothManager bluetoothManager;
  private boolean mScanning;
  private byte bleState; // 1:支持但未打开; 2:支持且已打开;
  private Context mContext;
  public String Pubkey;

  private LeScanCallback mLeScanCallback;
  private BleScanCallback scanCallback;
  private Handler scanHandler;
  private List<BluetoothDevice> devices;
  Application app;

  private static final byte BLE_STATE_NOT_SUPPORT = (byte) 0x00; // 0：不支持ble;
  private static final byte BLE_STATE_SUPPORT_NOT_OPEN = (byte) 0x01; // 支持但未打开
  private static final byte BLE_STATE_SUPPORT_AND_AVALIBLE = (byte) 0x02; // 支持且已打开

  private static final int APP_VERSION = 0x100;

  byte[] apduBuffer = new byte[261];
  private static final String CHARSET_UTF_8 = "UTF-8";

  public int MAX_CONTIANER_NAME_LENGTH = 15;

  private SHCAProvider(Application app) {
    this.app = app;

    mContext = app.getBaseContext();
    scanHandler = new Handler();
    devices = new ArrayList<BluetoothDevice>();
    mLeScanCallback = new LeScanCallback();
    initial_bluetooth_ble();

    bleUtil = NzBleUtil.getInstance(app);
  }

  public int getVersion() {
    return APP_VERSION;
  }

  public static SHCAProvider getInstance(Application app) {
    if (bleProvider == null) {
      bleProvider = new SHCAProvider(app);
    }

    return bleProvider;
  }

  public void setListener(BleStateListener listener) {
    bleUtil.setListener(listener);
  }

  private void initial_bluetooth_ble() {
    // 检查当前手机是否支持ble 蓝牙,如果不支持退出程序
    if (!mContext.getPackageManager().hasSystemFeature(
        PackageManager.FEATURE_BLUETOOTH_LE)) {
      // Toast.makeText(mContext, "该手机不支持BLE！",
      // Toast.LENGTH_SHORT).show();
      bleState = BLE_STATE_NOT_SUPPORT;
    }

    // 初始化 Bluetooth adapter, 通过蓝牙管理器得到一个参考蓝牙适配器(API必须在以上android4.3或以上和版本)
    bluetoothManager = (BluetoothManager) mContext
        .getSystemService(Context.BLUETOOTH_SERVICE);
    mBluetoothAdapter = bluetoothManager.getAdapter();

    // 检查设备上是否支持蓝牙
    if (mBluetoothAdapter == null) {
      // Toast.makeText(mContext, "该手机不支持蓝牙！", Toast.LENGTH_SHORT).show();
      bleState = BLE_STATE_NOT_SUPPORT;
    }

    if (!mBluetoothAdapter.isEnabled()) {
      // Intent enableBtIntent = new
      // Intent(BluetoothAdapter.ACTION_REQUEST_ENABLE);
      // mActivity.startActivityForResult(enableBtIntent,
      // REQUEST_ENABLE_BT);

      // Toast.makeText(mContext, "请先打开蓝牙！", Toast.LENGTH_SHORT).show();
      bleState = BLE_STATE_SUPPORT_NOT_OPEN;
    }

    bleState = BLE_STATE_SUPPORT_AND_AVALIBLE;
  }

  Runnable timeOutRunnable = new Runnable() {
    @Override
    public void run() {
      System.out.println("6666666666666");
      stopLeScan(true);
    }
  };

  // Device scan callback.
  private class LeScanCallback implements BluetoothAdapter.LeScanCallback {

    @Override
    public void onLeScan(final BluetoothDevice device, int rssi,
        byte[] scanRecord) {
      Logz.e("onLeScan",
          StringUtil.isEmptyString(device.getName()) ? device
              .getAddress().replace(":", "") : device.getName());

      boolean hasScanned = false;
      for (BluetoothDevice d : devices) {
        if (d.getAddress().equals(device.getAddress())) {// 已存在
          hasScanned = true;
          break;
        }
      }

      if (!hasScanned) {
        devices.add(device);
        scanCallback.onScannedWithDevice(device);
      }
    }
  }

  /**
   * 是否超时结束;
   *
   * @param isExpired : true:超时结束扫描； false:用户主动结束扫描
   */
  protected void stopLeScan(boolean isExpired) {
    Logz.e("stopLeScan", "stopLeScan");

    if (mScanning) {
      mBluetoothAdapter.stopLeScan(mLeScanCallback);

      if (!isExpired) {
        // 主动结束的话，超时不回调;
        scanHandler.removeCallbacks(timeOutRunnable);
      }
    }

    mScanning = false;

    if (isExpired) {
      if (devices.size() > 0) {
        this.scanCallback.onScannedFinish(devices);
      } else {
        this.scanCallback.onScannedFailed("未收到附近蓝雅4.0设备！");
      }
    }
  }

  /**
   * 开始扫描
   *
   * @param timeout ：单位为ms;
   */
  public void scanDevice(int timeout, BleScanCallback scanCallback) {
    this.scanCallback = scanCallback;

    if (bleState == BLE_STATE_NOT_SUPPORT) {
      this.scanCallback.onScannedFailed("手机不支持蓝牙4.0！");
    } else {
      if (!mBluetoothAdapter.isEnabled()) {
        this.scanCallback.onScannedFailed("请先开启蓝牙！");
      } else {
        scanHandler.postDelayed(timeOutRunnable, timeout);
        mScanning = true;
        devices.clear();
        mBluetoothAdapter.startLeScan(mLeScanCallback);
      }
    }
  }

  public void stopLeScan() {
    stopLeScan(false);
  }


  public void connectDevice(String name, String pin, int timeOut, BleStateListener listener) {
    stopLeScan(false);
    bleUtil.connect(name, pin, timeOut, listener);
  }

  /**
   * 查询连接状态
   *
   * @return： true:当前已连接； false:未连接;
   */
  public boolean isConnected() {
    return bleUtil.getNzBleState() == 16;
  }

  public byte[] transmitAPDU(byte[] apdu, short off, short len)
      throws Exception {
    return bleUtil.transmitApdu(apdu, off, len);
  }

  public byte[] transmitAPDU(byte[] apdu) throws Exception {
    return bleUtil.transmitApdu(apdu, (short) 0, (short) apdu.length);
  }

  /**
   * 关闭 SDK,断开与蓝牙卡的连接。
   */
  public void disconnect() {
    bleUtil.close();
  }

  /**
   * 关闭 SDK,断开与蓝牙卡的连接,如果是 SDK 打开的蓝牙模块,则关闭。
   */
  public void closeBle() {
    bleUtil.closeBle();
  }

  //------------------CA相关接口-------------------------------------
  private boolean hasSetEnv = false;

  private static final byte MIN_PIN_LENGTH = (byte) 2;
  private static final byte MAX_PIN_LENGTH = (byte) 20;

  /**
   * 环境初始化，选择应用;
   */
  public boolean setEnv(Context context) {
    hasSetEnv = false;

    try {
      byte[] res = bleProvider.transmitAPDU(CMD_SELECT_AID);

      if (StringUtil.checkSWofResp(res, (byte) 0x90, (byte) 0x00)) {
        hasSetEnv = true;
        mContext = context;
      } else {
        hasSetEnv = false;
      }
    } catch (Exception e) {
      // TODO Auto-generated catch block
      e.printStackTrace();
    }

    return hasSetEnv;
  }

  /**
   * 初始化超级用户的pin, 管理员pin及pin重试次数;
   */
  public int initDevice(String superPin, String adminPin, int retryNum) {

    if (!hasSetEnv) {
      return ENV_NOT_INIT.getResCode();
    }

    if (superPin.length() < MIN_PIN_LENGTH
        || superPin.length() > MAX_PIN_LENGTH) {
      return EnumError.KEY_PIN_INVALID.getResCode();
    }

    if (adminPin.length() < MIN_PIN_LENGTH
        || adminPin.length() > MAX_PIN_LENGTH) {
      return EnumError.KEY_PIN_INVALID.getResCode();
    }

    // 为超级管理员口令，管理员口令，用户口令，重试次数的TLV结构
    byte lc = (byte) (6 + superPin.length() + adminPin.length() + 1);

    apduBuffer[0] = (byte) 0x00;
    apduBuffer[1] = (byte) 0xD6;
    apduBuffer[2] = (byte) 0x00;
    apduBuffer[3] = (byte) 0x00;
    apduBuffer[4] = lc;

    short off = 5;

    //
    apduBuffer[off++] = SDKConstant.TAG_SUPER_PWD;
    apduBuffer[off++] = (byte) superPin.length();

    byte[] superPinBuff = superPin.getBytes();
    StringUtil.byteArrayCopy(superPinBuff, 0, apduBuffer, off,
        superPinBuff.length);
    off += superPinBuff.length;

    //
    apduBuffer[off++] = SDKConstant.TAG_MANAGER_PWD;
    apduBuffer[off++] = (byte) adminPin.length();

    byte[] adminPinBuff = adminPin.getBytes();
    StringUtil.byteArrayCopy(adminPinBuff, 0, apduBuffer, off,
        adminPinBuff.length);
    off += adminPinBuff.length;

    //
    apduBuffer[off++] = SDKConstant.TAG_PWD_REMAILS;
    apduBuffer[off++] = (byte) 0x01;
    apduBuffer[off++] = (byte) 0x0A;

    byte[] res;
    try {
      res = bleProvider.transmitAPDU(apduBuffer, (short) 0, (short) off);
      if (StringUtil.checkSWofResp(res, (byte) 0x90, (byte) 0x00)) {
        return EnumError.SUCCESS.getResCode();
      } else if (StringUtil.checkSWofResp(res, (byte) 0x62, (byte) 0x83)) {
        Toast.makeText(mContext, "应用已被临时锁定！", Toast.LENGTH_LONG).show();
      } else if (StringUtil.checkSWofResp(res, (byte) 0x93, (byte) 0x03)) {
        Toast.makeText(mContext, "应用已被永久锁定！", Toast.LENGTH_LONG).show();
      } else if (StringUtil.checkSW1ofResp(res, (byte) 0x63)) {
        Toast.makeText(
            mContext,
            "超级用户口令校验失败，剩余校验次数："
                + String.valueOf(res[res.length - 1]
                & (byte) 0x0F), Toast.LENGTH_LONG)
            .show();

        return EnumError.KEY_PIN_NO_MATCH.getResCode();
      }
    } catch (Exception e) {
      // TODO Auto-generated catch block
      e.printStackTrace();

      return EnumError.TRANSMIT_TIMEOUT.getResCode();
    }

    return EnumError.EVENT_SET_ERROR.getResCode();
  }

  /**
   * 修改容器的用户pin;
   */
  public int modifyUserPin(String containerName, String oldUserPin, String newUserPin) {
    return modifyPin(containerName, oldUserPin, newUserPin, SDKConstant.TAG_USER_PWD);
  }

  /**
   * 修改管理员pin
   */
  public int modifyAdminPin(String oldAdminPin, String newAdminPin) {
    return modifyPin(null, oldAdminPin, newAdminPin, SDKConstant.TAG_MANAGER_PWD);
  }

  private short appendContainerNameTlv(byte[] arr, short off,
      String containerName) throws Exception {
    byte[] cnBuff = containerName.getBytes(CHARSET_UTF_8);

    if (cnBuff.length > MAX_CONTIANER_NAME_LENGTH) {
      throw (new Exception("container name length is larger than 15"));
    }

    arr[off++] = (byte) SDKConstant.TAG_CONTAINER_NAME;
    arr[off++] = (byte) cnBuff.length;

    StringUtil.byteArrayCopy(cnBuff, (short) 0, arr, off, cnBuff.length);
    off += cnBuff.length;

    return off;
  }

  /**
   * 拼接Ascii串，返回加上拼接后的数据长度
   */
  private short appendTextValue(byte[] apduBuffer, short off, byte tag, String value) {
    apduBuffer[off++] = (byte) tag;

    byte[] bytes = value.getBytes();

    if (bytes.length < 0x80) {
      apduBuffer[off++] = (byte) bytes.length;
    } else if (bytes.length >= 0x80 && bytes.length < 0x100) {
      apduBuffer[off++] = (byte) 0x81;
      apduBuffer[off++] = (byte) (bytes.length & (byte) 0xFF);
    } else {
      apduBuffer[off++] = (byte) 0x82;
      apduBuffer[off++] = (byte) ((bytes.length >> (byte) 0x08) & (byte) 0xFF);
      apduBuffer[off++] = (byte) (bytes.length & (byte) 0xFF);
    }

    StringUtil.byteArrayCopy(bytes, (short) 0, apduBuffer, off, bytes.length);
    off += bytes.length;

    return off;
  }

  private int modifyPin(String containerName, String oldPin, String newPin, byte pinType) {
    if (!hasSetEnv) {
      return EnumError.ENV_NOT_INIT.getResCode();
    }

    if (oldPin.length() < MIN_PIN_LENGTH
        || oldPin.length() > MAX_PIN_LENGTH) {
      return EnumError.KEY_PIN_INVALID.getResCode();
    } else if (newPin.length() < MIN_PIN_LENGTH
        || newPin.length() > MAX_PIN_LENGTH) {
      return EnumError.KEY_PIN_INVALID.getResCode();
    }

    apduBuffer[0] = (byte) 0x00;
    apduBuffer[1] = (byte) 0x5E;
    apduBuffer[2] = (byte) 0x00;
    apduBuffer[3] = (byte) 0x00;

    short off = 5;

    if (containerName != null) {
      try {
        off = appendContainerNameTlv(apduBuffer, off, containerName);
      } catch (Exception e) {
        e.printStackTrace();
        return EnumError.INVALID_PARAMETER.getResCode();
      }
    }

    off = appendTextValue(apduBuffer, off, pinType, oldPin);
    off = appendTextValue(apduBuffer, off, pinType, newPin);

    apduBuffer[4] = (byte) (off - 5);

    byte[] res;
    try {
      res = bleProvider.transmitAPDU(apduBuffer, (short) 0, (short) off);
      if (StringUtil.checkSWofResp(res, (byte) 0x90, (byte) 0x00)) {
        return EnumError.SUCCESS.getResCode();
      } else if (StringUtil.checkSWofResp(res, (byte) 0x62, (byte) 0x83)) {
        Toast.makeText(mContext, "应用已被临时锁定！", Toast.LENGTH_LONG).show();
        return EnumError.KEY_PIN_LOCKED.getResCode();
      } else if (StringUtil.checkSWofResp(res, (byte) 0x93, (byte) 0x03)) {
        Toast.makeText(mContext, "应用已被永久锁定！", Toast.LENGTH_LONG).show();
      } else if (StringUtil.checkSW1ofResp(res, (byte) 0x63)) {
        Toast.makeText(
            mContext,
            "超级用户口令校验失败，剩余校验次数："
                + String.valueOf(res[res.length - 1]
                & (byte) 0x0F), Toast.LENGTH_LONG)
            .show();

        return EnumError.KEY_PIN_NO_MATCH.getResCode();
      }

    } catch (Exception e) {
      // TODO Auto-generated catch block
      e.printStackTrace();

      return EnumError.TRANSMIT_TIMEOUT.getResCode();
    }

    return EnumError.KEY_PIN_NO_MATCH.getResCode();
  }

  /**
   * 用管理员用户去解锁容器的pin;
   */
  public int unLockDevice(String containerName, String adminPin, String userPin) {
    if (!hasSetEnv) {
      return EnumError.ENV_NOT_INIT.getResCode();
    }

    apduBuffer[0] = (byte) 0x00;
    apduBuffer[1] = (byte) 0x24;
    apduBuffer[2] = (byte) 0x00;
    apduBuffer[3] = (byte) 0x00;
    apduBuffer[4] = (byte) 0x00;

    short off = 5;

    try {
      off = appendContainerNameTlv(apduBuffer, off, containerName);
    } catch (Exception e) {
      e.printStackTrace();
      return EnumError.INVALID_PARAMETER.getResCode();
    }

    // -----------------------------管理员pin-----------------------------------
    off = appendTextValue(apduBuffer, off, SDKConstant.TAG_MANAGER_PWD, adminPin);

    // -----------------------------用户pin-----------------------------------
    off = appendTextValue(apduBuffer, off, SDKConstant.TAG_USER_PWD, userPin);

    apduBuffer[4] = (byte) (off - 5);

    byte[] res;
    try {
      res = bleProvider.transmitAPDU(apduBuffer, (short) 0, (short) off);
      if (StringUtil.checkSWofResp(res, (byte) 0x90, (byte) 0x00)) {
        return EnumError.SUCCESS.getResCode();
      }
    } catch (Exception e) {
      // TODO Auto-generated catch block
      e.printStackTrace();

      return EnumError.TRANSMIT_TIMEOUT.getResCode();
    }

    return EnumError.KEY_PIN_NO_MATCH.getResCode();

  }

  /**
   * 参数类型
   *
   * @param infoType 1：介质类型< SOFT、AUDIO 、SD、OTG 、DOCK >）， 2：厂商介质信息， 3：介质唯一序列号，
   * 4：介质剩余空间<返回数字字符串，单位为M，如：143表示143M > ， 5：口令重试剩余次数
   */
  public String getDeviceInfo(int infoType) {
    if (!hasSetEnv) {
      return null;
    }

    apduBuffer[0] = (byte) 0x00;
    apduBuffer[1] = (byte) 0xCA;
    apduBuffer[2] = (byte) 0x00;
    if (infoType == 1) {
      apduBuffer[3] = (byte) SDKConstant.TAG_MEDIUM_TYPE; // 介质类型
    } else if (infoType == 2) {
      apduBuffer[3] = (byte) SDKConstant.TAG_PRODUCTOR_MEDIUM_INFO; // 厂商介质信息
    } else if (infoType == 3) {
      apduBuffer[3] = (byte) SDKConstant.TAG_SERIALS_ID; // 介质唯一序列号
    } else if (infoType == 4) {
      apduBuffer[3] = (byte) SDKConstant.TAG_SPACE_REMAIN; // 介质剩余空间
    } else if (infoType == 5) {
      apduBuffer[3] = (byte) SDKConstant.TAG_USER_PWD; // 口令重试剩余次数
    }

    apduBuffer[4] = (byte) 0x00;

    byte[] res;
    try {
      res = bleProvider.transmitAPDU(apduBuffer, (short) 0, (short) 5);
      if (StringUtil.checkSWofResp(res, (byte) 0x90, (byte) 0x00)) {
        if (infoType == (byte) 0x04) {
          // 剩余空间为10进制;
          return String.valueOf(StringUtil.byte2Short(res[2]));
        } else if (infoType == (byte) 0x05) {
          // T(05)L(02) 口令重试剩余次数 + 总次数
          return StringUtil.byteArrayToHexString(res, 3, (byte) 0x01);
        } else {
          return StringUtil.byteArrayToHexString(res, 2, res[1]);
        }
      }
    } catch (Exception e) {
      // TODO Auto-generated catch block
      e.printStackTrace();
    }

    return null;
  }

  /**
   * 生成密钥对
   *
   * @param algType: 算法类型（1：RSA-2048 ，2： SM2-256）
   */
  public int generateKeyPair(String containerName, int algType, String userPin) {
    if (!hasSetEnv) {
      return EnumError.ENV_NOT_INIT.getResCode();
    }

    if (algType != 1 && algType != 2) {
      return NO_FOUND_ALG_ERROR.getResCode();
    }

    apduBuffer[0] = (byte) 0x80;
    apduBuffer[1] = (byte) 0xCE;
    apduBuffer[2] = (byte) algType;
    apduBuffer[3] = (byte) 0x00;

    short off = 5;

    try {
      off = this.appendContainerNameTlv(apduBuffer, off, containerName);
    } catch (Exception e) {
      // TODO Auto-generated catch block
      e.printStackTrace();

      return EnumError.FAILED.getResCode();
    }

    // -----------------------------用户pin-----------------------------------
    off = appendTextValue(apduBuffer, off, SDKConstant.TAG_USER_PWD, userPin);

    apduBuffer[4] = (byte) (off - 5);

    byte[] res;
    try {
      res = bleProvider.transmitAPDU(apduBuffer, (short) 0, (short) off);

      if (StringUtil.checkSWofResp(res, (byte) 0x90, (byte) 0x00)) {
        return EnumError.SUCCESS.getResCode();
      } else if (StringUtil.checkSWofResp(res, (byte) 0x62, (byte) 0x83)) {
        Toast.makeText(mContext, "应用已被临时锁定！", Toast.LENGTH_LONG).show();
        return EnumError.KEY_PIN_LOCKED.getResCode();
      } else if (StringUtil.checkSWofResp(res, (byte) 0x93, (byte) 0x03)) {
        Toast.makeText(mContext, "应用已被永久锁定！", Toast.LENGTH_LONG).show();
        return EnumError.SPACE_LOCKED_FOREVER.getResCode();
      } else if (StringUtil.checkSWofResp(res, (byte) 0x62, (byte) 0x82)) {
        return EnumError.SPACE_NOT_ENOUGH.getResCode();
      }
    } catch (Exception e) {
      // TODO Auto-generated catch block
      e.printStackTrace();

      return EnumError.TRANSMIT_TIMEOUT.getResCode();
    }

    return EnumError.FAILED.getResCode();
  }

  /**
   * 导入X509证书，仅支持1024或2048的RSA证书；
   *
   * @param containerName : 容器名
   * @param keyType : 密钥类型（1：加密密钥，2：签名密钥）
   * @param cert : X509证书数据
   */
  public int importCertificate(String containerName, int keyType, byte[] cert, String userPin) {
    // ---------------------构造 证书
    if (keyType != 1 && keyType != 2) {
      return EnumError.KEY_TYPE_ERROR.getResCode();
    }

    CertificateFactory cf;
    try {
      cf = CertificateFactory.getInstance("X.509");
      ByteArrayInputStream in = new ByteArrayInputStream(cert);
      X509Certificate c = (X509Certificate) cf.generateCertificate(in);

      Logz.e("Algorithm", c.getPublicKey().getAlgorithm());

      if (!c.getPublicKey().getAlgorithm().equals("RSA")) {
        // 仅支持RSA证书
        return EnumError.NO_FOUND_ALG_ERROR.getResCode();
      }

      RSAPublicKey pubKey = (RSAPublicKey) c.getPublicKey();

      byte[] tempBuffer = new byte[3000];
      short off = 0;

      // -----------------容器名称---------------
      off = this.appendContainerNameTlv(tempBuffer, off, containerName);
      // containerName + String.valueOf(i));

      // ----------------X509证书数据TLV------------
      tempBuffer[off++] = SDKConstant.TAG_X509_CERTIFICATION;
      off = TLVTools.setLength(tempBuffer, off, (short) cert.length);
      StringUtil.byteArrayCopy(cert, (short) 0, tempBuffer, off,
          cert.length);
      off += cert.length;
      // ---------------------N----------------------
      tempBuffer[off++] = SDKConstant.TAG_N;
      byte[] nArr = pubKey.getModulus().toByteArray();

      // 只支持1024或2048的密钥;
      if (nArr.length < 128) {
        return EnumError.KEY_TYPE_ERROR.getResCode();
      }

      short pBytes = (short) (nArr.length % 128);
      off = TLVTools.setLength(tempBuffer, off,
          (short) (nArr.length - pBytes));
      StringUtil.byteArrayCopy(nArr, (short) pBytes, tempBuffer, off,
          nArr.length - pBytes);
      off += (nArr.length - pBytes);

      // ---------------------E----------------------
      tempBuffer[off++] = SDKConstant.TAG_E;
      byte[] eArr = pubKey.getPublicExponent().toByteArray();
      off = TLVTools.setLength(tempBuffer, off, (short) eArr.length);
      StringUtil.byteArrayCopy(eArr, (short) 0, tempBuffer, off,
          eArr.length);
      off += eArr.length;

      // -----------------------------用户pin-----------------------------------
      off = appendTextValue(tempBuffer, off, SDKConstant.TAG_USER_PWD, userPin);

      // -------------------组织命令发送--------------------------
      byte cmdIndex = 0;
      apduBuffer[0] = (byte) 0x80;
      apduBuffer[1] = (byte) 0xC8;
      apduBuffer[2] = (byte) ((byte) 0x80 | keyType); // X509证书

      short apduOff = 0;
      short apduLen = 0;

      do {
        if ((off - apduOff) >= 255) {
          apduBuffer[3] = cmdIndex;
          apduBuffer[4] = (byte) 0xFF;
          StringUtil.byteArrayCopy(tempBuffer, apduOff, apduBuffer,
              (short) 5, (short) 0xFF);

          apduLen = (5 + (short) 0xFF);
          apduOff += (short) 0xFF;
        } else {
          apduBuffer[3] = (byte) ((byte) cmdIndex | (byte) 0x80);
          apduBuffer[4] = (byte) ((off - apduOff) & (byte) 0xFF);
          StringUtil.byteArrayCopy(tempBuffer, apduOff, apduBuffer,
              (short) 5, (short) (off - apduOff));

          apduLen = (short) (5 + off - apduOff);
          apduOff = off;
        }

        byte[] res = bleProvider.transmitAPDU(apduBuffer, (short) 0,
            apduLen);

        if (StringUtil.checkSWofResp(res, (byte) 0x90, (byte) 0x00)) {
          cmdIndex++;
        } else if (StringUtil.checkSWofResp(res, (byte) 0x62,
            (byte) 0x83)) {
          Toast.makeText(mContext, "应用已被临时锁定！", Toast.LENGTH_LONG)
              .show();
          return EnumError.KEY_PIN_LOCKED.getResCode();
        } else if (StringUtil.checkSWofResp(res, (byte) 0x93,
            (byte) 0x03)) {
          Toast.makeText(mContext, "应用已被永久锁定！", Toast.LENGTH_LONG)
              .show();
          return EnumError.SPACE_LOCKED_FOREVER.getResCode();
        } else if (StringUtil.checkSWofResp(res, (byte) 0x69,
            (byte) 0x01)) {
          return EnumError.NO_LOGIN.getResCode();
        } else {
          return EnumError.FAILED.getResCode();
        }
      } while (apduOff < off);

      return EnumError.SUCCESS.getResCode();
    } catch (CertificateException e) {
      // TODO Auto-generated catch block
      e.printStackTrace();
      return EnumError.CERT_INVALID.getResCode();
    } catch (Exception e) {
      // TODO Auto-generated catch block
      e.printStackTrace();

      // return Result.TRANSMIT_TIMEOUT.getResCode();
    }

    return EnumError.CERT_SAVE_EXCEPTION.getResCode();
  }

  /**
   * 导出证书或公钥;
   *
   * @param exportType ：0:导出证书; 1:导出签名;
   * @param keyType ：1:加密证书；2:签名证书;
   */
  private byte[] exportCertificationOrPublicKey(String containerName,
      byte exportType, byte keyType) {
    try {
      // -----------------容器名称---------------
      apduBuffer[0] = (byte) 0x80;
      apduBuffer[1] = (byte) 0xC9;
      apduBuffer[2] = exportType;
      apduBuffer[3] = keyType;

      short off = 5;
      off = this.appendContainerNameTlv(apduBuffer, off, containerName);
      apduBuffer[4] = (byte) (off - 5);

      StringBuilder sb = new StringBuilder();

      byte[] res = bleProvider.transmitAPDU(apduBuffer, (short) 0, off);

      do {
        if (StringUtil.checkSWofResp(res, (byte) 0x90, (byte) 0x00)) {
          sb.append(StringUtil.byteArrayToHexString(res, (short) 0,
              res.length - 2));

          break;
        } else if (StringUtil.checkSW1ofResp(res, (byte) 0x61)) {
          sb.append(StringUtil.byteArrayToHexString(res, (short) 0,
              res.length - 2));

          apduBuffer[0] = (byte) 0x00;
          apduBuffer[1] = (byte) 0xC0;
          apduBuffer[2] = 0x00;
          apduBuffer[3] = 0x00;

          apduBuffer[4] = res[res.length - 1];
          res = bleProvider.transmitAPDU(apduBuffer, (short) 0,
              (short) 5);
        } else {
          return null;
        }
      } while (StringUtil.checkSW1ofResp(res, (byte) 0x61)
          || StringUtil.checkSWofResp(res, (byte) 0x90, (byte) 0x00));

      return StringUtil.hexStringToByteArray(sb.toString());
    } catch (Exception e) {
      // TODO Auto-generated catch block
      e.printStackTrace();
    }

    return null;
  }

  /**
   * 导出ASN.1的结构;
   */
  public byte[] exportCertificate(String containerName, int keyType) {
    byte[] res = exportCertificationOrPublicKey(containerName, (byte) 0x00,
        (byte) keyType);

    short vLen = TLVTools.getValueLength(res, (short) 0);
    byte tlWidth = TLVTools.getTLWidth(res, (short) 0);
    return StringUtil.subBytes(res, tlWidth, vLen);
  }

  /**
   * 导出ASN.1的结构;
   */
  public byte[] exportPubKey(String containerName, int keyType) {
    byte[] res = exportCertificationOrPublicKey(containerName, (byte) 0x01,
        (byte) keyType);

    // N + E TLV
    // 需要转成der编码输出;
    short nLen = TLVTools.getValueLength(res, (short) 0);
    byte nTLWidth = TLVTools.getTLWidth(res, (short) 0);
    String modeHex = StringUtil.byteArrayToHexString(StringUtil.subBytes(
        res, nTLWidth, nLen));

    short eLen = TLVTools.getValueLength(res, (short) (nLen + nTLWidth));
    byte eTLWidth = TLVTools.getTLWidth(res, (short) (nLen + nTLWidth));
    String exponentHex = StringUtil.byteArrayToHexString(StringUtil
        .subBytes(res, (short) (nTLWidth + nLen + eTLWidth), eLen));
    if (nTLWidth == (byte)0x02)
    {
      Pubkey = "C2"+Integer.toHexString(nLen)+modeHex+"C304"+exponentHex;
    }
    else if (nTLWidth == (byte)0x03)
    {
      Pubkey = "C281"+Integer.toHexString(nLen)+modeHex+"C304"+exponentHex;
    }
    else
    {
      Pubkey = "C282"+Integer.toHexString(nLen)+modeHex+"C304"+exponentHex;
    }
    KeyFactory factory;
    try {
      factory = KeyFactory.getInstance("RSA");

      BigInteger n = new BigInteger(modeHex, 16);
      BigInteger e = new BigInteger(exponentHex, 16);
      RSAPublicKeySpec spec = new RSAPublicKeySpec(n, e);

      RSAPublicKey pubkey = (RSAPublicKey) factory.generatePublic(spec);

      X509EncodedKeySpec x509EncodedKeySpec = new X509EncodedKeySpec(
          pubkey.getEncoded());

      return x509EncodedKeySpec.getEncoded();
    } catch (NoSuchAlgorithmException e1) {
      // TODO Auto-generated catch block
      e1.printStackTrace();
    } catch (InvalidKeySpecException e1) {
      // TODO Auto-generated catch block
      e1.printStackTrace();
    }

    return null;
  }

  public int createContainer(String containerName, String userPin) {

    if (!hasSetEnv) {
      return ENV_NOT_INIT.getResCode();
    }

    byte lc = (byte) (4 + containerName.length() + userPin.length());

    apduBuffer[0] = (byte) 0x00;
    apduBuffer[1] = (byte) 0xDD;
    apduBuffer[2] = (byte) 0x00;
    apduBuffer[3] = (byte) 0x00;
    apduBuffer[4] = lc;

    short off = 5;

    //containerName
    apduBuffer[off++] = SDKConstant.TAG_CONTAINER_NAME;
    apduBuffer[off++] = (byte) containerName.length();

    byte[] containerNameBuff = containerName.getBytes();
    StringUtil.byteArrayCopy(containerNameBuff, 0, apduBuffer, off,
        containerNameBuff.length);
    off += containerNameBuff.length;

    //userPIN
    apduBuffer[off++] = SDKConstant.TAG_USER_PWD;
    apduBuffer[off++] = (byte) userPin.length();

    byte[] userPinBuff = userPin.getBytes();
    StringUtil.byteArrayCopy(userPinBuff, 0, apduBuffer, off,
        userPinBuff.length);
    off += userPinBuff.length;

    byte[] res;
    try {
      res = bleProvider.transmitAPDU(apduBuffer, (short) 0, off);
      if (StringUtil.checkSWofResp(res, (byte) 0x90, (byte) 0x00)) {
        return EnumError.SUCCESS.getResCode();
      } else {
        return EnumError.CREATE_CONTAINER_ERROR.getResCode();
      }
    } catch (Exception ex) {
      return EnumError.TRANSMIT_TIMEOUT.getResCode();
    }
  }

  /**
   * 获取容器列表
   */
  public List<String> getContainerList() {
    List<String> containerList = new Vector<String>();

    apduBuffer[0] = (byte) 0x80;
    apduBuffer[1] = (byte) 0xCB;
    apduBuffer[2] = 0x00;
    apduBuffer[3] = 0x00;
    apduBuffer[4] = 0x00;

    byte[] res;
    try {
      res = bleProvider.transmitAPDU(apduBuffer, (short) 0, (short) 5);

      if (StringUtil.checkSWofResp(res, (byte) 0x90, (byte) 0x00)) {
        // 容器名称tlv串
        short off = 0;
        do {
          try {
            if (res[off + 1] > 0) {
              String containerName = new String(
                  StringUtil.subBytes(res, (short) (off + 2),
                      res[off + 1]), CHARSET_UTF_8);
              containerList.add(containerName);
            }
          } catch (UnsupportedEncodingException e) {
            // TODO Auto-generated catch block
            e.printStackTrace();
          }

          off += (short) (2 + res[off + 1]);
        } while (off < (res.length - 2));
      }
    } catch (Exception e1) {
      // TODO Auto-generated catch block
      e1.printStackTrace();
    }

    return containerList;
  }


  /**
   * 删除容器，需要验证相应的PIN；
   */
  public int deleteContainer(String containerName, String userPin) {

    try {
      apduBuffer[0] = (byte) 0x00;
      apduBuffer[1] = (byte) 0x0E;
      apduBuffer[2] = (byte) 0x00;
      apduBuffer[3] = (byte) 0x00;

      short off = 5;
      off = this.appendContainerNameTlv(apduBuffer, off, containerName);

      // -----------------------------用户pin-----------------------------------
      off = appendTextValue(apduBuffer, off, SDKConstant.TAG_USER_PWD, userPin);

      apduBuffer[4] = (byte) (off - 5);

      byte[] res = bleProvider.transmitAPDU(apduBuffer, (short) 0,
          (short) (5 + off));

      if (StringUtil.checkSWofResp(res, (byte) 0x90, (byte) 0x00)) {
        return EnumError.SUCCESS.getResCode();
      }

    } catch (Exception e) {
      // TODO Auto-generated catch block
      e.printStackTrace();

      return EnumError.TRANSMIT_TIMEOUT.getResCode();
    }

    return EnumError.NO_MATCH_ALIAS.getResCode();
  }


  /**
   * 请求随机数
   */
  public byte[] genRandom(int randomLen) {
    apduBuffer[0] = (byte) 0x00;
    apduBuffer[1] = (byte) 0x84;
    apduBuffer[2] = (byte) 0x00;
    apduBuffer[3] = (byte) 0x00;
    apduBuffer[4] = (byte) (randomLen & (byte) 0xFF);

    byte[] res;
    try {
      res = bleProvider.transmitAPDU(apduBuffer, (short) 0, (short) 5);

      if (StringUtil.checkSWofResp(res, (byte) 0x90, (byte) 0x00)) {
        return StringUtil.subBytes(res, (short) 0,
            (short) (res.length - 2));
      }

    } catch (Exception e) {
      // TODO Auto-generated catch block
      e.printStackTrace();
    }

    return null;
  }

  /**
   * 传输case 4指令，分断发送apdu，同时拼接收到的响应，再返回;
   *
   * @param tempBuffer : apdub数据；
   * @param off : apdub总长度;
   * @param needBlocks : 是否需要级联，需要的话，P2高bit为1表示为最后一块，低bit为index,不需要的话，P2 = 00;
   */
  public byte[] transmitInCase4(byte cla, byte ins, byte p1, byte p2,
      byte[] tempBuffer, short off, boolean needBlocks) {
    // -------------------组织命令发送--------------------------
    byte cmdIndex = 0;
    apduBuffer[0] = cla;
    apduBuffer[1] = ins;
    apduBuffer[2] = p1;

    short apduOff = 0;
    short apduLen = 0;
    byte[] res;

    do {
      if ((off - apduOff) >= 255) {
        apduBuffer[3] = cmdIndex;
        apduBuffer[4] = (byte) 0xFF;
        StringUtil.byteArrayCopy(tempBuffer, apduOff, apduBuffer,
            (short) 5, (short) 0xFF);

        apduLen = (5 + (short) 0xFF);
        apduOff += (short) 0xFF;
      } else {
        if (needBlocks) {
          apduBuffer[3] = (byte) ((byte) cmdIndex | (byte) 0x80);
        } else {
          apduBuffer[3] = p2;
        }
        apduBuffer[4] = (byte) ((off - apduOff) & (byte) 0xFF);
        StringUtil.byteArrayCopy(tempBuffer, apduOff, apduBuffer,
            (short) 5, (short) (off - apduOff));

        apduLen = (short) (5 + off - apduOff);
        apduOff = off;
      }

      try {
        res = bleProvider.transmitAPDU(apduBuffer, (short) 0, apduLen);
        if (StringUtil.checkSWofResp(res, (byte) 0x90, (byte) 0x00)) {
          cmdIndex++;
        } else if (StringUtil.checkSW1ofResp(res, (byte) 0x61)) {
          break;
        } else {
          return null;
        }
      } catch (Exception e) {
        // TODO Auto-generated catch block
        e.printStackTrace();
        return null;
      }

    } while (apduOff < off);

    StringBuilder sb = new StringBuilder();

    do {
      if (StringUtil.checkSWofResp(res, (byte) 0x90, (byte) 0x00)) {
        sb.append(StringUtil.byteArrayToHexString(res, (short) 0,
            res.length - 2));
        break;
      } else if (StringUtil.checkSW1ofResp(res, (byte) 0x61)) {
        sb.append(StringUtil.byteArrayToHexString(res, (short) 0,
            res.length - 2));

        apduBuffer[0] = (byte) 0x00;
        apduBuffer[1] = (byte) 0xC0;
        apduBuffer[2] = 0x00;
        apduBuffer[3] = 0x00;

        apduBuffer[4] = res[res.length - 1];
        try {
          res = bleProvider.transmitAPDU(apduBuffer, (short) 0,
              (short) 5);
        } catch (Exception e) {
          // TODO Auto-generated catch block
          e.printStackTrace();
          return null;
        }
      } else {
        return null;
      }
    } while (StringUtil.checkSW1ofResp(res, (byte) 0x61)
        || StringUtil.checkSWofResp(res, (byte) 0x90, (byte) 0x00));

    return StringUtil.hexStringToByteArray(sb.toString());
  }

  /**
   * RSA运算中，待运算原始数据的长度，必须为公钥模长。
   *
   * @param cert : X509证书数据
   * @param inData : 待加密数据
   */
  public byte[] pubKeyEncryption(byte[] cert, byte[] inData) {
    try {
      CertificateFactory cf = CertificateFactory.getInstance("X.509");

      ByteArrayInputStream in = new ByteArrayInputStream(cert);
      X509Certificate c;

      c = (X509Certificate) cf.generateCertificate(in);

      Logz.e("Algorithm", c.getPublicKey().getAlgorithm());

      if (!c.getPublicKey().getAlgorithm().equals("RSA")) {
        // 仅支持RSA证书
        return null;
      }

      RSAPublicKey pubKey = (RSAPublicKey) c.getPublicKey();

      byte[] tempBuffer = new byte[3000];
      short off = 0;

      // ---------------------N----------------------
      tempBuffer[off++] = SDKConstant.TAG_N;
      byte[] nArr = pubKey.getModulus().toByteArray();

      short pBytes = (short) (nArr.length % 128);

      // 只支持1024或2048的密钥;
      if (nArr.length < 128 || inData.length != (nArr.length - pBytes)) {
        return null;
      }

      off = TLVTools.setLength(tempBuffer, off,
          (short) (nArr.length - pBytes));
      StringUtil.byteArrayCopy(nArr, (short) pBytes, tempBuffer, off,
          nArr.length - pBytes);
      off += (nArr.length - pBytes);

      // ---------------------E----------------------
      tempBuffer[off++] = SDKConstant.TAG_E;
      byte[] eArr = pubKey.getPublicExponent().toByteArray();
      off = TLVTools.setLength(tempBuffer, off, (short) eArr.length);
      StringUtil.byteArrayCopy(eArr, (short) 0, tempBuffer, off,
          eArr.length);
      off += eArr.length;

      // ---------------------- 待签名数据 -----------------
      tempBuffer[off++] = SDKConstant.TAG_ORIGINAL_TEXT;
      off = TLVTools.setLength(tempBuffer, off, (short) inData.length);
      StringUtil.byteArrayCopy(inData, (short) 0, tempBuffer, off,
          (short) inData.length);
      off += (short) inData.length;

      // 由外部传入的公钥对传入数据加密
      byte[] res = transmitInCase4((byte) 0x80, (byte) 0x4C, (byte) 0x00,
          (byte) 0x00, tempBuffer, (short) off, true);

      if (res != null) {
        // 返回的是TLV结构
        byte tlWidth = TLVTools.getTLWidth(res, (short) 0);
        short vLenth = TLVTools.getValueLength(res, (short) 0);
        return StringUtil.subBytes(res, tlWidth, vLenth);
      } else {
        return null;
      }
    } catch (CertificateException e) {
      // TODO Auto-generated catch block
      e.printStackTrace();
    } catch (Exception e) {
      // TODO Auto-generated catch block
      e.printStackTrace();
    }

    return null;
  }

  /**
   * 查找证书公钥类型（如：RSA-1024 或 SM2-256），使用公钥进行加密运算。 RSA运算中，待运算原始数据的长度，必须为公钥模长。
   *
   * @param containName 容器名
   * @param keyType 密钥类型（1：加密密钥，2：签名密钥）
   * @param inData 待加密数据
   * @param userPin 该容器对应的用户pin;
   */
  public byte[] pubKeyEncryption(String containName, int keyType,
      byte[] inData, String userPin) {
    byte[] tempBuffer = new byte[3000];
    short off = 0;

    // -----------------容器名称---------------
    try {
      off = this.appendContainerNameTlv(tempBuffer, off, containName);
    } catch (Exception e) {
      // TODO Auto-generated catch block
      e.printStackTrace();

      return null;
    }

    // ---------------------- 待签名数据 -----------------
    tempBuffer[off++] = SDKConstant.TAG_ORIGINAL_TEXT;
    off = TLVTools.setLength(tempBuffer, off, (short) inData.length);
    StringUtil.byteArrayCopy(inData, (short) 0, tempBuffer, off,
        (short) inData.length);
    off += (short) inData.length;

    // -----------------------------用户pin-----------------------------------
    off = appendTextValue(apduBuffer, off, SDKConstant.TAG_USER_PWD, userPin);

    // -------------------组织命令发送--------------------------
    // 由指定容器中的公钥对传入数据加密
    byte[] res = transmitInCase4((byte) 0x80, (byte) 0x4C, (byte) 0x01,
        (byte) 0x00, tempBuffer, (short) off, true);

    if (res != null) {
      // 返回的是TLV结构
      byte tlWidth = TLVTools.getTLWidth(res, (short) 0);
      short vLenth = TLVTools.getValueLength(res, (short) 0);
      return StringUtil.subBytes(res, tlWidth, vLenth);
    } else {
      return null;
    }
  }

  /**
   *
   * @param containerName
   * @param keyType
   * @param encryptedData
   * @return
   */
  public byte[] priKeyDecryption(String containerName, int keyType,
      byte[] encryptedData, String userPin) {
    // 容器名称 + 待解密数据
    byte[] tempBuffer = new byte[3000];
    short off = 0;

    // -----------------容器名称---------------
    try {
      off = this.appendContainerNameTlv(tempBuffer, off, containerName);
    } catch (Exception e) {
      // TODO Auto-generated catch block
      e.printStackTrace();

      return null;
    }
    // -----------------待解密数据 -------------
    tempBuffer[off++] = SDKConstant.TAG_ENCRYPT_OR_SIGNNED_TEXT;
    off = TLVTools.setLength(tempBuffer, off, (short) encryptedData.length);
    StringUtil.byteArrayCopy(encryptedData, (short) 0, tempBuffer, off,
        (short) encryptedData.length);
    off += (short) encryptedData.length;

    // -----------------------------用户pin-----------------------------------
    off = appendTextValue(apduBuffer, off, SDKConstant.TAG_USER_PWD, userPin);

    // -------------------组织命令发送--------------------------
    byte[] res = transmitInCase4((byte) 0x80, (byte) 0x48, (byte) keyType,
        (byte) 0x00, tempBuffer, (short) off, true);

    if (res != null) {
      // 返回的是TLV结构
      byte tlWidth = TLVTools.getTLWidth(res, (short) 0);
      short vLenth = TLVTools.getValueLength(res, (short) 0);
      return StringUtil.subBytes(res, tlWidth, vLenth);
    } else {
      return null;
    }
  }


  /**
   * 数据签名
   *
   * @param keyType 密钥类型（1：加密密钥，2：签名密钥）
   * @param hashType 摘要算法类型（1：SHA-1， 2：SHA-256， 3： SM3）
   * @param isHash 待签名原文是否哈希(true 为hash值，false为原文，默认为false原文)
   * @return 签名值（符合der编码）
   */
  public byte[] signData(String containerName, int keyType, int hashType,
      byte[] inData, boolean isHash, String userPin) {
    try {
      byte[] tempBuffer = new byte[3000];
      short off = 0;
      // 容器名称 + 摘要算法类型 +待签名数据。各字段全是TLV
      // -----------------容器名称---------------
      off = this.appendContainerNameTlv(tempBuffer, off, containerName);
      // ------------------ 摘要算法类型 --------
      tempBuffer[off++] = SDKConstant.TAG_DIGEST_ALG_TYPE;
      tempBuffer[off++] = (byte) 0x01;
      tempBuffer[off++] = (byte) hashType;

      // ---------------------- 待签名数据 -----------------
      tempBuffer[off++] = SDKConstant.TAG_ORIGINAL_TEXT;
      off = TLVTools.setLength(tempBuffer, off, (short) inData.length);
      StringUtil.byteArrayCopy(inData, (short) 0, tempBuffer, off,
          (short) inData.length);
      off += (short) inData.length;

      // -----------------------------用户pin-----------------------------------
      off = appendTextValue(apduBuffer, off, SDKConstant.TAG_USER_PWD, userPin);

      byte p2 = (byte) ((byte) keyType | (isHash ? (byte) 0x80
          : (byte) 0x00)); // P12签名证书
      byte[] res = transmitInCase4((byte) 0x80, (byte) 0x4E, p2,
          (byte) 0x00, tempBuffer, (short) off, true);

      if (res != null) {
        // 返回的是TLV结构
        byte tlWidth = TLVTools.getTLWidth(res, (short) 0);
        short vLenth = TLVTools.getValueLength(res, (short) 0);
        return StringUtil.subBytes(res, tlWidth, vLenth);
      } else {
        return null;
      }
    } catch (Exception e) {

    }

    return null;
  }

  /**
   * @param containername : 容器名
   * @param publickey : 公钥
   * @param inData : 原文
   * @param signedValue : 签名值
   * @param hashType : 摘要算法类型（1：SHA-1， 2：SHA-256， 3： SM3）
   * @param isHash : 待签名原文是否哈希(true 为hash值，false为原文，默认为false原文)
   */
  public boolean verifySignedData(String containername ,String publickey, byte[] inData,
      byte[] signedValue, int hashType, boolean isHash) {

      // RSA公钥（N，E ）+ 摘要算法类型 + 原文 + 待验签数据。各字段全是TLV摘要算法类型：（1：SHA-1，
      // 2：SHA-256， 3： SM3）
      byte[] tempBuffer = new byte[3000];
      short off = 0;

      // --------------N ,E---------------
      StringUtil.byteArrayCopy(StringUtil.hexStringToByteArray(publickey),(short) 0,tempBuffer,off,(short)StringUtil.hexStringToByteArray(publickey).length);
      off += (short)StringUtil.hexStringToByteArray(publickey).length;

      // ------------------ 摘要算法类型 --------
      tempBuffer[off++] = SDKConstant.TAG_DIGEST_ALG_TYPE;
      tempBuffer[off++] = (byte) 0x01;
      tempBuffer[off++] = (byte) hashType;

      // ------------------原文--------------
      tempBuffer[off++] = SDKConstant.TAG_ORIGINAL_TEXT;
      off = TLVTools.setLength(tempBuffer, off, (short) inData.length);
      StringUtil.byteArrayCopy(inData, (short) 0, tempBuffer, off,
          (short) inData.length);
      off += (short) inData.length;

      // -----------------待验签数据 -------------
      tempBuffer[off++] = SDKConstant.TAG_ENCRYPT_OR_SIGNNED_TEXT;
      off = TLVTools.setLength(tempBuffer, off,
          (short) signedValue.length);
      StringUtil.byteArrayCopy(signedValue, (short) 0, tempBuffer, off,
          (short) signedValue.length);
      off += (short) signedValue.length;

      // -------------------组织命令发送--------------------------
      byte cmdIndex = 0;
      apduBuffer[0] = (byte) 0x80;
      apduBuffer[1] = (byte) 0x49;
      apduBuffer[2] = isHash ? (byte) 0x80 : (byte) 0x00; // P12签名证书

      short apduOff = 0;
      short apduLen = 0;

      do {
        if ((off - apduOff) >= 255) {
          apduBuffer[3] = cmdIndex;
          apduBuffer[4] = (byte) 0xFF;
          StringUtil.byteArrayCopy(tempBuffer, apduOff, apduBuffer,
              (short) 5, (short) 0xFF);

          apduLen = (5 + (short) 0xFF);
          apduOff += (short) 0xFF;
        } else {
          apduBuffer[3] = (byte) ((byte) cmdIndex | (byte) 0x80);
          apduBuffer[4] = (byte) ((off - apduOff) & (byte) 0xFF);
          StringUtil.byteArrayCopy(tempBuffer, apduOff, apduBuffer,
              (short) 5, (short) (off - apduOff));

          apduLen = (short) (5 + off - apduOff);
          apduOff = off;
        }

        byte[] res;
        try {
          res = bleProvider.transmitAPDU(apduBuffer, (short) 0,
              apduLen);

          if (StringUtil.checkSWofResp(res, (byte) 0x90, (byte) 0x00)) {
            cmdIndex++;
          } else {
            return false;
          }
        } catch (Exception e) {
          // TODO Auto-generated catch block
          e.printStackTrace();

          return false;
        }

      } while (apduOff < off);

      return true;
  }

  /**
   * 指令透传
   */
  public byte[] transiveAPDU(byte[] arg0) throws Exception {
    // TODO Auto-generated method stub
    return bleProvider.transmitAPDU(arg0, (short) 0, (short) arg0.length);
  }


}
